package com.blacksea.authserver.service.manager;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.blacksea.authserver.dal.dataobject.ClientDO;
import com.blacksea.authserver.dal.dataobject.CodeDO;
import com.blacksea.authserver.dal.enumclass.CodeStatusEnum;
import com.blacksea.authserver.service.repository.ClientRepository;
import com.blacksea.authserver.service.repository.CodeRepository;
import com.blacksea.authserver.util.DateUtil;
import com.blacksea.authserver.util.RandomUtil;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import java.util.Date;

import javax.annotation.Resource;

/**
 * AuthorizationManagerImpl
 *
 * @author blacksea3(jxt) 2021/4/11 21:09
 */
@Service(value = "authorizationManager")
public class AuthorizationManagerImpl implements AuthorizationManager {
    private static final int MAX_GENERATE_NEW_CODE_TRY_TIME = 10;

    private static final int CODE_LENGTH = 6;

    private static final int EXPIRE_SECONDS = 180;

    @Resource(name = "clientRepository")
    private ClientRepository clientRepository;

    @Resource(name = "codeRepository")
    private CodeRepository codeRepository;

    @Override
    public boolean isValidClient(String clientId, String redirectUri) {
        return clientRepository.count(new LambdaQueryWrapper<ClientDO>().eq(ClientDO::getClientId, clientId)
            .eq(ClientDO::getRedirectUri, redirectUri)
        ) == 1;
    }

    @Override
    public Pair<Boolean, String> checkClientAndGenerateCode(String clientId, String redirectUri) {
        if (!isValidClient(clientId, redirectUri)) {
            return new ImmutablePair<>(false, "INVALID CLIENT");
        } else {
            int loopTime = 0;
            do {
                String code = RandomUtil.generateCode(CODE_LENGTH);
                Date secondsLater = DateUtil.generateDateAfterSeconds(EXPIRE_SECONDS);
                if (codeRepository.save(new CodeDO(code, CodeStatusEnum.VALID, secondsLater))) {
                    return new ImmutablePair<>(true, code);
                }
                loopTime++;
            } while (loopTime < MAX_GENERATE_NEW_CODE_TRY_TIME);
            return new ImmutablePair<>(false, "GENERATE CODE ERROR");
        }
    }
}
